#include "Circle_H.h"
#include "PointH.h"
#include <conio.h>
#include <iostream>
#include "gotoxyH.h"
#include <stdio.h>
#include <math.h>



void gotoxy(int, int);
void clrscr();

void Circle::init()
{

	//If Adding Data members, Please remember to update the operator assignment "="
    m_Radius = 0;
	m_symb = '*';
	m_dirX = m_dirY = m_tempDirX = m_tempDirY = 0;
    m_prevDirX = m_prevDirY = 0;

}

Circle& Circle::operator=(const Circle& copyObj){ //Again there's a dry copy, no need to implement operator =. it's doing the same thing.  anyway I'm moving dirX,dirY to Shape
	//Checks self copy - if yes nothing to do
	if (this == &copyObj) return *this;
	//copy
	m_Radius = copyObj.m_Radius;
	m_center = copyObj.m_center;
	m_symb = copyObj.m_symb;
	m_dirX = copyObj.m_dirX, m_dirY = copyObj.m_dirY, m_tempDirX = copyObj.m_tempDirX, m_tempDirY = copyObj.m_dirY;
	m_prevDirX = copyObj.m_prevDirX, m_prevDirY = copyObj.m_prevDirY;
	//return existing object 
	return *this;
}

void Circle::getPos(int &x, int &y)
{
	m_center.getPos(x,y);
}

void Circle::setPos(int x, int y)
{
	m_center.setPos(x,y);
}

void Circle::getSize(int &r)
{
	r = m_Radius;
}

void Circle::setSize(int x)
{
	m_Radius = x;
}

void Circle::draw(int drawingOption, Screen * s)
{
	if(drawingOption == 0) draw1(drawingOption,s);
	else draw2(drawingOption,s);
}


void Circle::draw1(int drawingOption, Screen * s)
{
	int x,y,radius,centerx,centery;
	
	radius = m_Radius;

	m_center.getPos(centerx,centery);
	//Drawing Option - Full Circle
	for(int y=-radius; y<=radius; y++)
		for(int x=-radius; x<=radius; x++)
			if(x*x+y*y <= radius*radius)
			{
				gotoxy(centerx+x, centery+y);
				cout << m_symb;
			}
	
	/*for(int y=-radius; y<=radius; y++)
		for(int x=-radius; x<=radius; x++)
			if(x*x+y*y == radius*radius)
			{
				gotoxy(centerx+x, centery+y);
				cout << m_symb;
			}*/
	
}


void Circle::getCirclePoints4(Point &p1, Point &p2, Point &p3, Point &p4)
{
  int posX, posY;
  int r;
  
  this->getPos(posX,posY);
  this->getSize(r);
	
  p1.setPos(posX+r, posY); 
  p2.setPos(posX-r, posY); 
  p3.setPos(posX, posY-r); 
  p4.setPos(posX, posY+r); 
}

void Circle::draw2(int drawingOption, Screen * s)
{
  int circleX, circleY;
  int radius;

  getPos(circleX,circleY);
  getSize(radius);
  
  int checking = -radius;
  int x = radius;
  int y = 0;
 
  while (x >= y)
  {  
    
	drawPoints8(circleX, circleY, x, y, drawingOption, s);
 
    checking += y;
    ++y;
    checking += y;
 
    if (checking >= 0)
    {
      checking -= x;
      --x;
      checking -= x;
    }
  }

}



void Circle::drawPoints8(int circleX, int circleY, int x, int y, int drawingOption, Screen * s)
{
  drawPoints4(circleX, circleY, x, y, drawingOption, s);
  if (x != y) drawPoints4(circleX, circleY, y, x, drawingOption, s);
}



void Circle::drawPoints4(int circleX, int circleY, int x, int y, int drawingOption, Screen * s)
{

	if(isInScreen(circleX + x, circleY + y)) {
	  
	  if(!s){
		  gotoxy(circleX + x, circleY + y); cout << "*";}
	  else 
		  s->setToScreenBuffer(circleY + y,circleX + x);
	}

  if (x != 0){ 
	  
	  if(isInScreen(circleX - x, circleY + y)) {
		  
		  if(!s){
			  gotoxy(circleX - x, circleY + y); cout << "*";}
		  else
			    s->setToScreenBuffer(circleY + y, circleX - x);
	  }
  }	  
		 
  if (y != 0){
	  
	  if(isInScreen(circleX + x, circleY - y)) {
		  
		  if(!s){
			  gotoxy(circleX + x, circleY - y); cout << "*";}
		  else 
			  s->setToScreenBuffer(circleY - y, circleX + x);
	  }
  }

  if (x != 0 && y != 0){
	  
	  if(isInScreen(circleX - x, circleY - y)) {
		  
		  if(!s){
			  gotoxy(circleX - x, circleY - y); cout << "*";}
		  else
			  s->setToScreenBuffer(circleY - y, circleX - x);
		 
	  }
  }
}




bool Circle::isInScreen(int x, int y) // is coord. in screen ?
{
	if( x >=0 && x <= MAX_SCR_WID-1)
		if (y >= 0 && y <= MAX_SCR_LEN-1)
			return true;
		
	return false;
}



bool Circle::isDirectionsResetBorders()
{
  Point pLeft, pRight, pUp, pDown;	


  bool clashed = false;

  int circleX, circleY;
  int radius;

  this->getPos(circleX,circleY);
  this->getSize(radius);
  
  int checking = -radius;
  int x = radius;
  int y = 0;
 
  if (x >= y && !clashed)
  {
    this->getCirclePoints4(pRight, pLeft, pUp, pDown);
 
    if(isDirectionsResetBordersCirclesPerPoint(this, pRight)) clashed = true;
	if(isDirectionsResetBordersCirclesPerPoint(this, pLeft)) clashed = true;
	if(isDirectionsResetBordersCirclesPerPoint(this, pUp)) clashed = true;
	if(isDirectionsResetBordersCirclesPerPoint(this, pDown)) clashed = true;
  }

	if(clashed) return true;

	return false;
}

bool Circle::isDirectionsResetBordersCirclesPerPoint(Circle * c, Point p)
{
    int x,y;
	bool chengeMade = false;
	int dirX, dirY;

	p.getPos(x,y);
	c->getIntegerDirectionExplicitly(dirX,dirY);
	
	if(x+dirX > 80 || x+dirX < -1) { 

		c->resetDirectionX();
		dirX = -dirX; 
		chengeMade = true;
	}

	if(y+dirY > 25 || y+dirY < -1) { 
		
		c->resetDirectionY();
		dirY = -dirY;
		chengeMade = true;
	}

   if(chengeMade) return true;

	return false;

}


bool Circle::isContain(Circle * c2)
{
	
	int x,y,radius;
	int xC2,yC2,c2Radius;

	this->getPos(x,y);
	this->getSize(radius);
	c2->getPos(xC2,yC2);
	c2->getSize(c2Radius);

	if((xC2-c2Radius >= x-radius) && (xC2+c2Radius <= x+radius) && (yC2-c2Radius >= y-radius) && (yC2+c2Radius <= y+radius)) return true;

	return false;
}


bool Circle::isOverlap(Circle * c2)
{
	int x,y,radius;
	int xC2,yC2,c2Radius;

	this->getPos(x,y);
	this->getSize(radius);
	c2->getPos(xC2,yC2);
	c2->getSize(c2Radius);

	if (xC2+c2Radius > x-radius && xC2-c2Radius < x+radius && yC2+c2Radius > y-radius &&  yC2-c2Radius < y+radius) return true;

	return false;
}


bool Circle::getHitPoint(Circle * c2, Point &pHit)
{
  int c1CircleX, c1CircleY, c2CircleX, c2CircleY;
  int c1Radius, c2Radius;
  bool hitFlag = false;

  Point c1p1, c1p2, c1p3, c1p4, c1p5, c1p6, c1p7, c1p8, c2p1, c2p2, c2p3, c2p4, c2p5, c2p6, c2p7, c2p8;

  getPos(c1CircleX,c1CircleY);
  getSize(c1Radius);
  c2->getPos(c2CircleX,c2CircleY);
  c2->getSize(c2Radius);

  int checkingC1 = -c1Radius;
  int xC1 = c1Radius;
  int yC1 = 0;
 
  while (xC1 >= yC1 && hitFlag == false)
  {
	  
     get4Points(c1CircleX, c1CircleY, xC1, yC1, c1p1, c1p2, c1p3, c1p4);
	 {
		if(isPointInCircleEnvelop(c1p1,c2))
		{
			pHit = c1p1;
		    hitFlag = true;
		}

		if(isPointInCircleEnvelop(c1p2,c2))
		{
            pHit = c1p2;
			hitFlag = true;
	    }

		if(isPointInCircleEnvelop(c1p3,c2))
		{
			pHit = c1p3;
			hitFlag = true;
	    }

		if(isPointInCircleEnvelop(c1p4,c2))
		{
            pHit = c1p4;
			hitFlag = true;
	    }
	 }

	 if(xC1!=yC1 && hitFlag == false)
	 {
	    get4Points(c1CircleX, c1CircleY, yC1, xC1, c1p1, c1p2, c1p3, c1p4);
		{
	     if(isPointInCircleEnvelop(c1p1,c2))
		 {
			pHit = c1p1;
		    hitFlag = true;
		 }

		 if(isPointInCircleEnvelop(c1p2,c2))
		 {
            pHit = c1p2;
			hitFlag = true;
		 }

		 if(isPointInCircleEnvelop(c1p3,c2))
		 {
			pHit = c1p3;
			hitFlag = true;
		 }

		 if(isPointInCircleEnvelop(c1p4,c2))
		 {
            pHit = c1p4;
			hitFlag = true;
		 }
		}
	 }

	checkingC1 += yC1;
    ++yC1;
    checkingC1 += yC1;
 
    if (checkingC1 >= 0)
    {
      checkingC1 -= xC1;
      --xC1;
      checkingC1 -= xC1;
	}
  }


  if (hitFlag) return true;
  
  return false;
}
		  

bool Circle::isPointInCircleEnvelop(const Point &p1, Circle * c2)
{
	int c2CircleX, c2CircleY;
    int c2Radius;
	bool hitFlag = false;

	Point c2p1, c2p2, c2p3, c2p4;
	
	c2->getPos(c2CircleX,c2CircleY);
    c2->getSize(c2Radius);

	int checkingC2 = -c2Radius;
    int xC2 = c2Radius;
    int yC2 = 0;

	while (xC2 >= yC2 && hitFlag==false)
    {  
    
	  get4Points(c2CircleX, c2CircleY, xC2, yC2, c2p1, c2p2, c2p3, c2p4);
		  if(isPointEqual4Points(p1,c2p1, c2p2, c2p3, c2p4)) hitFlag = true;

	  if(xC2!=yC2 && hitFlag==false)
	  {
	    get4Points(c2CircleX, c2CircleY, yC2, xC2, c2p1, c2p2, c2p3, c2p4);
		    if(isPointEqual4Points(p1,c2p1, c2p2, c2p3, c2p4)) hitFlag = true;
	  }

	  checkingC2 += yC2;
      ++yC2;
      checkingC2 += yC2;
 
      if (checkingC2 >= 0)
      {
        checkingC2 -= xC2;
        --xC2;
        checkingC2 -= xC2;
      }
	}

	if(hitFlag) return true;

	return false;
}


bool Circle::isPointEqual4Points(Point pCheck, Point p1, Point p2, Point p3, Point p4)
{
	if(pCheck==p1) return true;
	if(pCheck==p2) return true;
	if(pCheck==p3) return true;
	if(pCheck==p4) return true;

	return false;
}
	


void Circle::get4Points(int CircleX, int CircleY, int x, int y, Point &p1, Point &p2, Point &p3, Point &p4){

	p1.setPos(CircleX + x, CircleY + y);
	p2.setPos(CircleX - x, CircleY + y);
	p3.setPos(CircleX + x, CircleY - y);
	p4.setPos(CircleX - x, CircleY - y);

}

void Circle::get8Points(int CircleX, int CircleY, int x, int y, Point &p1, Point &p2, Point &p3, Point &p4){

  get4Points(CircleX, CircleY, x, y, p1, p2, p3, p4);
  if (x != y) get4Points(CircleX, CircleY, y, x, p1, p2, p3, p4);

}


bool Circle::isXaxis(Point p)
{
	int x,y;
	double sqrtResult;

	p.getPos(x,y);

	sqrtResult = sqrt (double((m_Radius*m_Radius)/2));

	if(y >= (double)y-sqrtResult && y <= (double)y+sqrtResult) return true;

	return false;
}


bool Circle::isYaxis(Point p)
{
	int x,y;
	double sqrtResult;

	p.getPos(x,y);

	sqrtResult = sqrt (double((m_Radius*m_Radius)/2));

	if(x >= (double)x-sqrtResult && x <= (double)x+sqrtResult) return true;

	return false;
}


bool Circle::isPointIn(int x, int y) 
{
    Circle tempCircle;

	tempCircle.setPos(x,y);
	tempCircle.setSize(1);

	if (this->isOverlap(&tempCircle)) return true;

	return false;
	
}